home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 November: Tool Chest / Dev.CD Nov 96 TC / Dev.CD Nov 96 TC.toast / Sample Code / Snippets / Sound / SndPlayDoubleBuffer / _source / DoubleBufferFromFile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-06  |  29.2 KB  |  1,062 lines  |  [TEXT/CWIE]

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    Routines demonstrating how to play a sound from disk using SndPlayDoubleBuffer.
  5. **
  6. **    by Mark Cookson, Apple Developer Technical Support
  7. **
  8. **    File:    DoubleBufferFromFile.c
  9. **
  10. **    Copyright ©1996 Apple Computer, Inc.
  11. **    All rights reserved.
  12. **
  13. **    You may incorporate this sample code into your applications without
  14. **    restriction, though the sample code has been provided "AS IS" and the
  15. **    responsibility for its operation is 100% yours.  However, what you are
  16. **    not permitted to do is to redistribute the source as "Apple Sample
  17. **    Code" after having made changes. If you're going to re-distribute the
  18. **    source, we require that you make it clear in the source that the code
  19. **    was descended from Apple Sample Code, but that you've made changes.
  20. */
  21.  
  22. #include "DoubleBufferFromFile.h"
  23.  
  24. /*    Purpose:        This creates a new SoundInfo structure and initializes
  25.                     it by calling the private function ASoundInit.
  26.     Side Effects:    None.
  27. */
  28. /*-----------------------------------------------------------------------*/
  29. SoundInfoPtr    ASoundNew                (OSErr *theErr)
  30. /*-----------------------------------------------------------------------*/
  31. {
  32.     SoundInfoPtr    theSoundInfo    = nil;
  33.  
  34.     *theErr = noErr;
  35.     theSoundInfo = (SoundInfoPtr)NewPtrClear (sizeof (SoundInfo));
  36.  
  37.     if (MemError () != noErr || theSoundInfo == nil) {
  38.         *theErr = kInitErr;
  39.     }
  40.     else {
  41.         *theErr = ASoundInit (theSoundInfo);
  42.     }
  43.  
  44.     if (*theErr != noErr) {
  45.         DebugPrint ("\pError in ASoundNew");
  46.     }
  47.  
  48.     return theSoundInfo;
  49. }
  50.  
  51. /*
  52.     Purpose:        Display a StandardFile dialog to select a file.
  53.                     Opens the file selected by the user.
  54.     Side Effects:    None.
  55. */
  56. /*-----------------------------------------------------------------------*/
  57. OSErr            ASoundGetFileToPlay        (SoundInfoPtr theSoundInfo)
  58. /*-----------------------------------------------------------------------*/
  59. {
  60.     FileFilterUPP        myFilterUPP    = nil;
  61.     OSErr                theErr        = noErr;
  62.     short                i            = 0;
  63.     Boolean                good        = false;
  64.  
  65.     if (IsValid (theSoundInfo)) {
  66.         myFilterUPP = NewFileFilterProc (ASoundFileFilter);
  67.         if ((theSoundInfo->globals.ggestaltStandardFileAttr & gestaltStandardFile58) == false) {
  68.             StandardFileReply    theSFReply;
  69.  
  70.             StandardGetFile (myFilterUPP, kNoFirstFiltering, nil, &theSFReply);
  71.             theSoundInfo->vRefNum = theSFReply.sfFile.vRefNum;
  72.             if (theSFReply.sfGood == true) {
  73.                 switch (theSFReply.sfType) {
  74.                     case kSNDResource:
  75.                     case kResource:
  76.                         theErr = FSpOpenRF (&theSFReply.sfFile, fsCurPerm, &(theSoundInfo->refNum));
  77.                         break;
  78.                     case kCompressedAIFFFile:
  79.                     case kUncompressedAIFFFile:
  80.                     case kWAVEFile:
  81.                     case kAUFile:
  82.                         theErr = FSpOpenDF (&theSFReply.sfFile, fsCurPerm, &(theSoundInfo->refNum));
  83.                         break;
  84.                     default:
  85.                         DebugPrint ("\pASoundGetFileToPlay should have never executed this line");
  86.                 }
  87.                 if (theErr != noErr) {
  88.                     DebugPrint ("\pCouldn't open file");
  89.                 }
  90.                 else {
  91.                     theSoundInfo->fileType = theSFReply.sfType;
  92.                     for (i = 0; i <= theSFReply.sfFile.name[0]+1; i++)
  93.                         theSoundInfo->theName[i] = theSFReply.sfFile.name[i];
  94.                 }
  95.             }
  96.             else {
  97.                 theErr = userCanceledErr;
  98.             }
  99.         }
  100.         else {
  101.             SFReply            theSFReply;
  102.             Point            where        = {kInit, kInit};
  103.             Rect            screenRect    = GetMainScreenRect();
  104.             long            dirID        = kInit,
  105.                             procID        = kInit;
  106.  
  107.             where.h = screenRect.right / kHorizAdjust;    /* This will put the SFGetFile dialog in the same place */
  108.             where.v = screenRect.bottom / kVertAdjust;    /* as the StandardGetFile dialog (or really close). */
  109.             if ((GetMBarHeight() + kOne) > where.h) {
  110.                 where.h = GetMBarHeight() + kOne;
  111.             }
  112.             SFGetFile (where, nil, myFilterUPP, kNoFirstFiltering, nil, nil, &theSFReply);
  113.             good = theSFReply.good;
  114.             if (theSFReply.good == true) {
  115.                 theErr = GetWDInfo (theSFReply.vRefNum, &(theSoundInfo->vRefNum), &dirID, &procID);
  116.                 if (theErr == noErr) {
  117.                     switch (theSFReply.fType) {
  118.                         case kSNDResource:
  119.                         case kResource:
  120.                             theErr = HOpenRF (theSoundInfo->vRefNum, dirID, theSFReply.fName, fsCurPerm, &(theSoundInfo->refNum));
  121.                             break;
  122.                         case kCompressedAIFFFile:
  123.                         case kUncompressedAIFFFile:
  124.                         case kWAVEFile:
  125.                         case kAUFile:
  126.                             theErr = HOpenDF (theSoundInfo->vRefNum, dirID, theSFReply.fName, fsCurPerm, &(theSoundInfo->refNum));
  127.                             break;
  128.                         default:
  129.                             DebugPrint ("\pASoundGetFileToPlay should have never executed this line");
  130.                     }
  131.                     if (theErr != noErr) {
  132.                         DebugPrint ("\pCouldn't open file");
  133.                     }
  134.                     else {
  135.                         theSoundInfo->fileType = theSFReply.fType;
  136.                         for (i = 0; i <= theSFReply.fName[0]+1; i++)
  137.                             theSoundInfo->theName[i] = theSFReply.fName[i];
  138.                     }
  139.                 }
  140.                 else {
  141.                     theErr = kFileErr;
  142.                     DebugPrint ("\pCouldn't translate working directory");
  143.                 }
  144.             }
  145.             else {
  146.                 theErr = userCanceledErr;
  147.             }
  148.         }
  149.         DisposeRoutineDescriptor (myFilterUPP);
  150.     }
  151.     else {
  152.         theErr = kNilPtrErr;
  153.     }
  154.  
  155.     if (theErr != noErr && theErr != userCanceledErr) {
  156.         DebugPrint ("\pError in ASoundGetFileToPlay");
  157.     }
  158.  
  159.     return theErr;
  160. }
  161.  
  162. /*
  163.     Purpose:        Checks a file to see if its header can be parsed
  164.                     and the file can be played.
  165.  
  166.                     This will return an error if the sound will not play,
  167.                     returning noErr means that sound will play.
  168.  
  169.                     Parsing a header can take some time, this routine
  170.                     is a canidate for speed improvements.
  171.     Side Effects:    None.
  172. */
  173. /*-----------------------------------------------------------------------*/
  174. OSErr            ASoundCanThisPlay        (CInfoPBPtr theFileInfo)
  175. /*-----------------------------------------------------------------------*/
  176. {
  177.     SoundInfoPtr    theSoundInfo    = nil;
  178.     long            dataStart        = kInit,
  179.                     sndLength        = kInit;
  180.     OSErr            theErr            = noErr,
  181.                     closeErr        = noErr;
  182.  
  183.     if (theFileInfo  != nil) {
  184.         theSoundInfo = ASoundNew (&theErr);
  185.         if (theErr == noErr) {
  186.             theSoundInfo->vRefNum = theFileInfo->hFileInfo.ioVRefNum;
  187.             theSoundInfo->fileType = theFileInfo->hFileInfo.ioFlFndrInfo.fdType;
  188.             theErr = HOpenDF (theFileInfo->hFileInfo.ioVRefNum, theFileInfo->hFileInfo.ioFlParID, theFileInfo->hFileInfo.ioNamePtr, fsRdPerm, &theSoundInfo->refNum);
  189.             if (theErr == noErr) {
  190.                 switch (theSoundInfo->fileType) {
  191.                     case kCompressedAIFFFile:
  192.                     case kUncompressedAIFFFile:
  193.                         theErr = ASoundGetAIFFHeader (theSoundInfo, &dataStart, &sndLength);
  194.                         break;
  195.                     case kWAVEFile:
  196.                         theErr = ASoundGetWAVEHeader (theSoundInfo, &dataStart, &sndLength);
  197.                         break;
  198.                     case kAUFile:
  199.                         theErr = ASoundGetULAWHeader (theSoundInfo, &dataStart, &sndLength);
  200.                         break;
  201.                     case kSNDResource:
  202.                     case kResource:
  203.                         theErr = noErr;        /* For now, assume it will play */
  204.                         break;
  205.                     default:
  206.                         /* The file type is not one that we can even parse. */
  207.                         theErr = kUnknownFormat;
  208.                         break;
  209.                 }
  210.             }
  211.         }
  212.     }
  213.     else {
  214.         theErr = kNilPtrErr;
  215.     }
  216.  
  217.     closeErr = FSClose (theSoundInfo->refNum);
  218.     DisposeRoutineDescriptor (ASoundGetSoundCallBack (theSoundInfo));
  219.     DisposePtr ((Ptr)theSoundInfo);
  220.  
  221.     if (closeErr != noErr) {
  222.         theErr = closeErr;
  223.     }
  224.  
  225.     if (theErr != noErr && theErr != kUnknownFormat) {
  226.         DebugPrint ("\pError in ASoundCanThisPlay");
  227.     }
  228.  
  229.     return theErr;
  230. }
  231.  
  232. /*
  233.     Purpose:        This function is called to get ready to play a sound.
  234.                     Use this if you want to make sure that there is enough
  235.                     memory to play the sound.
  236.     Side Effects:    This will call routines that will allocate memory needed
  237.                     to all of the various structures needed by the Sound Manager
  238.                     and memory to be used as the sounds' buffers.
  239. */
  240. /*-----------------------------------------------------------------------*/
  241. OSErr            ASoundReadyForPlaying    (SoundInfoPtr theSoundInfo,
  242.                                         unsigned long bufferSize)
  243. /*-----------------------------------------------------------------------*/
  244. {
  245.     OSErr                theErr        = noErr;
  246.  
  247.     if (IsValid (theSoundInfo)) {
  248.         if (theSoundInfo->globals.gSupportsSPDB == false) {
  249.             DebugPrint ("\pThis machine doesn't support SoundPlayDoubleBuffer, can't play!");
  250.             theErr = kNoSPDBErr;
  251.         }
  252.         else {
  253.             if ((ASoundGetBytesCopied (theSoundInfo) <= kMaxAIFFHeaderSize) && theSoundInfo->paused == false) {        /* do we want to start at the begining of the file? */
  254.                 theSoundInfo->soundDone = false;
  255.                 theErr = SndNewChannel (&(theSoundInfo->chan), sampledSynth, nil, ASoundGetSoundCallBack (theSoundInfo));
  256.                 if (theErr != noErr) {
  257.                     DebugPrint ("\pSndNewChannel error!");
  258.                 }
  259.                 else {
  260.                     theErr = SetUpSoundHeader (theSoundInfo, bufferSize);
  261.                     if (theErr == noErr) {
  262.                         theErr = ASoundPrimeBuffers (theSoundInfo);
  263.                         ASoundSetCurBuffer (theSoundInfo, kOne);
  264.                     }
  265.                 }
  266.             }
  267.             else {
  268.                 theErr = ASoundPrimeBuffers (theSoundInfo);
  269.             }
  270.         }
  271.     }
  272.     else {
  273.         theErr = kNilPtrErr;
  274.     }
  275.  
  276.     if (theErr != noErr) {
  277.         DebugPrint ("\pError in ASoundReadyForPlaying!");
  278.         (void)ASoundDonePlaying (theSoundInfo, kCloseFile + kFreeMem);
  279.     }
  280.  
  281.     return theErr;
  282. }
  283.  
  284. /*
  285.     Purpose:        Call this after you have called ASoundReadyForPlaying to
  286.                     start playing the sound you prepaired.
  287.     Side Effects:    Starts the sound playing.
  288. */
  289. /*-----------------------------------------------------------------------*/
  290. OSErr            ASoundPlay                (SoundInfoPtr theSoundInfo)
  291. /*-----------------------------------------------------------------------*/
  292. {
  293.     OSErr                theErr        = noErr;
  294.  
  295.     if (IsValid (theSoundInfo)) {
  296.         if (theSoundInfo->playing == false || theSoundInfo->paused == true) {
  297.             if (theSoundInfo->globals.gSupportsSPDB == false) {
  298.                 theErr = kNoSPDBErr;
  299.                 DebugPrint ("\pThis machine doesn't support SoundPlayDoubleBuffer, can't play!");
  300.             }
  301.             else {
  302.                 if (theSoundInfo->paused == false) {
  303.                     theErr = SndPlayDoubleBuffer (theSoundInfo->chan, (SndDoubleBufferHeaderPtr)&(theSoundInfo->doubleHeader));
  304.                     if (theErr == noErr) {
  305.                         theErr = InstallCallBack (theSoundInfo);
  306.                         if (theErr == noErr) {
  307.                             theSoundInfo->playing = true;
  308.                         }
  309.                     }
  310.                 }
  311.             }
  312.         }
  313.     }
  314.     else {
  315.         theErr = kNilPtrErr;
  316.     }
  317.  
  318.     if (theErr != noErr) {
  319.         DebugPrint ("\pError in ASoundPlay!");
  320.         (void)ASoundDonePlaying (theSoundInfo, kCloseFile + kFreeMem);
  321.     }
  322.  
  323.     return theErr;
  324. }
  325.  
  326. /*
  327.     Purpose:        Wrapper function called to start playing a sound.
  328.                     Use this if you are pretty sure the sound will play, or
  329.                     just don't care specifically what goes wrong.
  330.     Side Effects:    This will call routines that will allocate memory needed
  331.                     for all of the various structures needed by the Sound Manager
  332.                     and memory to be used as the sounds' buffers.
  333. */
  334. /*-----------------------------------------------------------------------*/
  335. OSErr            ASoundStartPlaying        (SoundInfoPtr theSoundInfo,
  336.                                         unsigned long bufferSize)
  337. /*-----------------------------------------------------------------------*/
  338. {
  339.     OSErr                theErr        = noErr;
  340.  
  341.     theErr = ASoundReadyForPlaying (theSoundInfo, bufferSize);
  342.     if (theErr == noErr) {
  343.         theErr = ASoundPlay (theSoundInfo);
  344.     }
  345.  
  346.     if (theErr != noErr) {
  347.         DebugPrint ("\pError in ASoundStartPlaying!");
  348.         (void)ASoundDonePlaying (theSoundInfo, kCloseFile + kFreeMem);
  349.     }
  350.  
  351.     return theErr;
  352. }
  353.  
  354. /*
  355.     Purpose:        Stops the currently playing sound.
  356.     Side Effects:    Stopping the currently playing sound will cause the
  357.                     sound completion routine to run.
  358. */
  359. /*-----------------------------------------------------------------------*/
  360. OSErr            ASoundStop                (SoundInfoPtr theSoundInfo)
  361. /*-----------------------------------------------------------------------*/
  362. {
  363.     SndCommand        theCmd        = {quietCmd, kInit, kInit};
  364.     OSErr            theErr        = noErr;
  365.  
  366.     if (StrictIsValid (theSoundInfo)) {
  367.         theErr = SndDoImmediate (theSoundInfo->chan, &theCmd);
  368.         if (theErr == noErr) {
  369.             theSoundInfo->playing = false;
  370.             theSoundInfo->paused = false;
  371.         }
  372.     }
  373.     else {
  374.         theErr = kNilPtrErr;
  375.     }
  376.  
  377.     if (theErr != noErr) {
  378.         DebugPrint ("\pError in ASoundStop");
  379.     }
  380.  
  381.     return theErr;
  382. }
  383.  
  384. /*
  385.     Purpose:        Wrapper so the user doesn't have to keep track of if
  386.                     the sound is playing or not.
  387.     Side Effects:    If resuming a sound and the user had also called
  388.                     ASoundPauseForAdjust this will reinstall the sound
  389.                     completion callback.
  390. */
  391. /*-----------------------------------------------------------------------*/
  392. OSErr            ASoundPause                (SoundInfoPtr theSoundInfo)
  393. /*-----------------------------------------------------------------------*/
  394. {
  395.     OSErr            theErr        = noErr;
  396.  
  397.     if (StrictIsValid (theSoundInfo)) {
  398.         if (theSoundInfo->paused == false) {
  399.             theErr = PauseSound (theSoundInfo);
  400.         }
  401.         else {
  402.             theErr = ResumeSound (theSoundInfo);
  403.         }
  404.     }
  405.     else {
  406.         theErr = kNilPtrErr;
  407.     }
  408.  
  409.     if (theErr != noErr) {
  410.         DebugPrint ("\pError in ASoundPause");
  411.     }
  412.  
  413.     return theErr;
  414. }
  415.  
  416. /*
  417.     Purpose:        If the sound is paused, resume playing.  If the sound is
  418.                     playing, pause playing.
  419.                     This differs from ASoundPause because it actually stops
  420.                     the sound instead of pausing it.  When the sound is
  421.                     paused for adjusting you can reset where the sound will
  422.                     next start playing from without having to play the
  423.                     remainder of the current buffer.  This routine is used
  424.                     for the QuickTime style playing.
  425.     Side Effects:    Removes the callback from the sound channel because
  426.                     otherwise while adjusting the sound the Sound Manager
  427.                     would call our clean up routine.
  428.                     When resuming a sound ASoundStartPlaying will install
  429.                     our callback routine if necessary (if the sound wasn't
  430.                     already paused).
  431. */
  432. /*-----------------------------------------------------------------------*/
  433. OSErr            ASoundPauseForAdjust    (SoundInfoPtr theSoundInfo)
  434. /*-----------------------------------------------------------------------*/
  435. {
  436.     SndCommand        theCmd            = {kInit, kInit, kInit};
  437.     OSErr            theErr            = noErr;
  438.     static Fixed    oldRate            = kInit;
  439.  
  440.     if (StrictIsValid (theSoundInfo)) {
  441.         if (theSoundInfo->adjusting == false) {
  442.             theCmd.cmd = flushCmd;            /* so the sound completion callback doesn't get called */
  443.             theErr = SndDoImmediate (theSoundInfo->chan, &theCmd);
  444.             if (theErr == noErr) {
  445.                 theSoundInfo->adjusting = true;
  446.                 theCmd.cmd = quietCmd;
  447.                 theErr = SndDoImmediate (theSoundInfo->chan, &theCmd);
  448.                 if (theErr == noErr) {
  449.                     theSoundInfo->hasBeenAdjusted = true;
  450.                     theSoundInfo->playing = false;
  451.                 }
  452.             }
  453.         }
  454.         else {
  455.             theSoundInfo->adjusting = false;
  456.             ASoundStartPlaying (theSoundInfo, nil);
  457.         }
  458.     }
  459.     else {
  460.         theErr = kNilPtrErr;
  461.     }
  462.  
  463.     if (theErr != noErr) {
  464.         DebugPrint ("\pError in ASoundPauseForAdjust");
  465.     }
  466.  
  467.     return theErr;
  468. }
  469.  
  470. /*
  471.     Purpose:        Sound is done playing, dispose of the memory we no
  472.                     longer need.
  473.     Side Effects:    None.
  474. */
  475. /*-----------------------------------------------------------------------*/
  476. OSErr            ASoundDonePlaying        (SoundInfoPtr theSoundInfo,
  477.                                         unsigned long options)
  478. /*-----------------------------------------------------------------------*/
  479. {
  480.     myParamBlockRec    *myPB            = nil;
  481.     OSErr            theErr            = noErr;
  482.     short             i                = kInit,
  483.                     savedVRefNum    = kInit,
  484.                     savedRefNum        = kInit;
  485.  
  486.     if (IsValid (theSoundInfo)) {
  487.         theSoundInfo->soundDone = false;            /* so we don't get called multiple times */
  488.  
  489.         savedVRefNum = theSoundInfo->vRefNum;
  490.         savedRefNum = theSoundInfo->refNum;
  491.         if ((options == kCloseFile) || (options > kCloseFile + kFreeMem)) {
  492.             DebugPrint ("\pInvalid selector passed to ASoundDonePlaying");
  493.             theErr = kBadValue;
  494.         }
  495.         else {
  496.             myPB = (myParamBlockRec*)theSoundInfo->doubleHeader.dbhBufferPtr[kDBBufOne]->dbUserInfo[kPBPtr];
  497.             if (options > kNoOptions) {
  498.                 if (myPB != nil) {
  499.                     if (options == kCloseFile + kFreeMem) {
  500.                         theErr = FSClose (myPB->pb.ioParam.ioRefNum);
  501.                     }
  502.                     if (theErr == noErr) {
  503.                         for (i = kInit; i <= kOne; i++) {
  504.                             DisposeRoutineDescriptor (((myParamBlockRec*)theSoundInfo->doubleHeader.dbhBufferPtr[i]->dbUserInfo[kPBPtr])->pb.ioParam.ioCompletion);
  505.                             DisposePtr ((Ptr)theSoundInfo->doubleHeader.dbhBufferPtr[i]->dbUserInfo[kPBPtr]);
  506.                             /* Have to unhold memory that was held */
  507.                             UnholdMemory ((Ptr)theSoundInfo->doubleHeader.dbhBufferPtr[i], sizeof(SndDoubleBuffer) + ASoundGetBufferSize (theSoundInfo));
  508.                             DisposePtr ((Ptr)theSoundInfo->doubleHeader.dbhBufferPtr[i]);
  509.                         }
  510.                     }
  511.                     else {
  512.                         DebugPrint ("\pFSClose error!");
  513.                     }
  514.                     theErr = SndDisposeChannel (theSoundInfo->chan, true);
  515.                     DisposeRoutineDescriptor (ASoundGetSoundCallBack (theSoundInfo));
  516.                     DisposeRoutineDescriptor (theSoundInfo->doubleHeader.dbhDoubleBack);
  517.                     if (theErr != noErr) {
  518.                         DebugPrint ("\pSndDisposeChannel error!");
  519.                     }
  520.                 }
  521.             }
  522.  
  523.             if (options == kNoOptions) {
  524.                 ASoundSetBytesCopied (theSoundInfo, theSoundInfo->dataStart);
  525.                 ASoundSetCurBuffer (theSoundInfo, kStart);
  526.                 theSoundInfo->doubleHeader.dbhBufferPtr[kDBBufOne]->dbFlags ^= dbLastBuffer;
  527.                 theSoundInfo->doubleHeader.dbhBufferPtr[kDBBufTwo]->dbFlags ^= dbLastBuffer;
  528.             }
  529.             if (options == kFreeMem) {
  530.                 ASoundInit (theSoundInfo);
  531.                 theSoundInfo->vRefNum = savedVRefNum;
  532.                 theSoundInfo->refNum = savedRefNum;
  533.             }
  534.             else {
  535.                 if (options == kCloseFile + kFreeMem) {
  536.                     ASoundInit (theSoundInfo);
  537.                 }
  538.             }
  539.         }
  540.     }
  541.     else {
  542.         theErr = kNilPtrErr;
  543.     }
  544.  
  545.     if (theErr != noErr) {
  546.         DebugPrint ("\pError in ASoundDonePlaying");
  547.     }
  548.  
  549.     return theErr;
  550. }
  551.  
  552. /*
  553.     Purpose:        Returns the name of the file containing the currently
  554.                     playing sound.
  555.     Side Effects:    None.
  556. */
  557. /*-----------------------------------------------------------------------*/
  558. OSErr            ASoundGetSoundName        (SoundInfoPtr theSoundInfo,
  559.                                         Str63 theName)
  560. /*-----------------------------------------------------------------------*/
  561. {
  562.     OSErr            theErr        = noErr;
  563.     short            i            = 0;
  564.  
  565.     if (StrictIsValid (theSoundInfo) && theName != nil) {
  566.         for (i = 0; i <= theSoundInfo->theName[0]+1; i++)
  567.             theName[i] = theSoundInfo->theName[i];
  568.     }
  569.  
  570.     return theErr;
  571. }
  572.  
  573. /*
  574.     Purpose:        Gets the number of the current buffer
  575.                     (in the range 1 to ASoundGetNumBuffers()) of the
  576.                     currently playing sound.
  577.     Side Effects:    None.
  578. */
  579. /*-----------------------------------------------------------------------*/
  580. long            ASoundGetCurBuffer        (SoundInfoPtr theSoundInfo)
  581. /*-----------------------------------------------------------------------*/
  582. {
  583.     long        returnValue        = kInit;
  584.     OSErr        theErr            = noErr;
  585.  
  586.     if (StrictIsValid (theSoundInfo)) {
  587.         returnValue = theSoundInfo->currentBuffer;
  588.     }
  589.     else {
  590.         theErr = kNilPtrErr;
  591.         returnValue = nil;
  592.     }
  593.  
  594.     if (theErr != noErr) {
  595.         DebugPrint ("\pError in ASoundGetCurBuffer");
  596.     }
  597.  
  598.     return returnValue;
  599. }
  600.  
  601. /*
  602.     Purpose:        Sets which buffer should be the next buffer to play
  603.                     from (in the range 1 to ASoundGetNumBuffers())
  604.                     for the currently playing sound.
  605.     Side Effects:    None.
  606. */
  607. /*-----------------------------------------------------------------------*/
  608. OSErr            ASoundSetCurBuffer        (SoundInfoPtr theSoundInfo,
  609.                                         long newValue)
  610. /*-----------------------------------------------------------------------*/
  611. {
  612.     OSErr        theErr            = noErr;
  613.  
  614.     if (IsValid (theSoundInfo)) {
  615.         if ((newValue >= kStart) && (newValue <= ASoundGetNumBuffers (theSoundInfo))) {
  616.             theSoundInfo->currentBuffer = newValue;
  617.         }
  618.         else {
  619.             theErr = kBadRange;
  620.         }
  621.     }
  622.     else {
  623.         theErr = kNilPtrErr;
  624.     }
  625.  
  626.     return theErr;
  627. }
  628.  
  629. /*
  630.     Purpose:        Gets the number of buffers that the currently playing
  631.                     sound will need to play in its entirety.
  632.     Side Effects:    None.
  633. */
  634. /*-----------------------------------------------------------------------*/
  635. long            ASoundGetNumBuffers        (SoundInfoPtr theSoundInfo)
  636. /*-----------------------------------------------------------------------*/
  637. {
  638.     long        returnValue        = kInit;
  639.     OSErr        theErr            = noErr;
  640.  
  641.     if (IsValid (theSoundInfo)) {
  642.         returnValue = theSoundInfo->numBuffers;
  643.     }
  644.     else {
  645.         theErr = kNilPtrErr;
  646.         returnValue = nil;
  647.     }
  648.  
  649.     if (theErr != noErr) {
  650.         DebugPrint ("\pError in ASoundGetNumBuffers");
  651.     }
  652.  
  653.     return returnValue;
  654. }
  655.  
  656. /*
  657.     Purpose:        Gets the length (in bytes) of the currently playing
  658.                     sound.  This number does not include any header bytes.
  659.     Side Effects:    None.
  660. */
  661. /*-----------------------------------------------------------------------*/
  662. long            ASoundGetNumTotalBytes    (SoundInfoPtr theSoundInfo)
  663. /*-----------------------------------------------------------------------*/
  664. {
  665.     long        returnValue        = kInit;
  666.     OSErr        theErr            = noErr;
  667.  
  668.     if (IsValid (theSoundInfo)) {
  669.         returnValue = theSoundInfo->bytesTotal;
  670.     }
  671.     else {
  672.         theErr = kNilPtrErr;
  673.         returnValue = nil;
  674.     }
  675.  
  676.     if (theErr != noErr) {
  677.         DebugPrint ("\pError in ASoundGetNumTotalBytes");
  678.     }
  679.  
  680.     return returnValue;
  681. }
  682.  
  683. /*
  684.     Purpose:        Gets the number of bytes that will be played by the end
  685.                     of the current buffer of the currently playing sound.
  686.     Side Effects:    None.
  687. */
  688. /*-----------------------------------------------------------------------*/
  689. long            ASoundGetBytesCopied    (SoundInfoPtr theSoundInfo)
  690. /*-----------------------------------------------------------------------*/
  691. {
  692.     long        returnValue        = kInit;
  693.     OSErr        theErr            = noErr;
  694.  
  695.     if (IsValid (theSoundInfo)) {
  696.         returnValue = theSoundInfo->bytesCopied;
  697.     }
  698.     else {
  699.         theErr = kNilPtrErr;
  700.         returnValue = nil;
  701.     }
  702.  
  703.     if (theErr != noErr) {
  704.         DebugPrint ("\pError in ASoundGetBytesCopied");
  705.     }
  706.  
  707.     return returnValue;
  708. }
  709.  
  710. /*
  711.     Purpose:        Sets the location in the file where the next buffer
  712.                     should be filled from for the currently playing sound.
  713.     Side Effects:    None.
  714. */
  715. /*-----------------------------------------------------------------------*/
  716. OSErr            ASoundSetBytesCopied    (SoundInfoPtr theSoundInfo,
  717.                                         long newValue)
  718. /*-----------------------------------------------------------------------*/
  719. {
  720.     OSErr        theErr            = noErr;
  721.  
  722.     if (IsValid (theSoundInfo)) {
  723.         if (newValue >= theSoundInfo->dataStart || newValue == kInit) {
  724.             theSoundInfo->bytesCopied = newValue;
  725.         }
  726.         else {
  727.             theErr = kBadValue;
  728.         }
  729.     }
  730.     else {
  731.         theErr = kNilPtrErr;
  732.     }
  733.  
  734.     if (theErr != noErr) {
  735.         DebugPrint ("\pError in ASoundSetBytesCopied");
  736.     }
  737.  
  738.     return theErr;
  739. }
  740.  
  741. /*
  742.     Purpose:        Gets the size of a buffer of the currently playing
  743.                     sound.  Multiply by two to know how much memory is
  744.                     reserved for buffering the currently playing sound.
  745.     Side Effects:    None.
  746. */
  747. /*-----------------------------------------------------------------------*/
  748. long            ASoundGetBufferSize        (SoundInfoPtr theSoundInfo)
  749. /*-----------------------------------------------------------------------*/
  750. {
  751.     long        returnValue        = kInit;
  752.     OSErr        theErr            = noErr;
  753.  
  754.     if (IsValid (theSoundInfo)) {
  755.         returnValue = theSoundInfo->doubleBufferSize;
  756.     }
  757.     else {
  758.         theErr = kNilPtrErr;
  759.         returnValue = nil;
  760.     }
  761.  
  762.     if (theErr != noErr) {
  763.         DebugPrint ("\pError in ASoundGetBufferSize");
  764.     }
  765.  
  766.     return returnValue;
  767. }
  768.  
  769. /*
  770.     Purpose:        Gets the UPP for the function that should be called when
  771.                     the currently playing sound finishes.
  772.     Side Effects:    None.
  773. */
  774. /*-----------------------------------------------------------------------*/
  775. SndCallBackUPP    ASoundGetSoundCallBack    (SoundInfoPtr theSoundInfo)
  776. /*-----------------------------------------------------------------------*/
  777. {
  778.     SndCallBackUPP        returnValue        = nil;
  779.     OSErr                theErr            = noErr;
  780.  
  781.     if (IsValid (theSoundInfo)) {
  782.         returnValue = theSoundInfo->theSoundCallBackUPP;
  783.     }
  784.     else {
  785.         theErr = kNilPtrErr;
  786.         returnValue = nil;
  787.     }
  788.  
  789.     if (theErr != noErr) {
  790.         DebugPrint ("\pError in ASoundGetSoundCallBack");
  791.     }
  792.  
  793.     return returnValue;
  794. }
  795.  
  796. /*
  797.     Purpose:        Sets the function that should be called when the the
  798.                     currently playing sound finishes.
  799.     Side Effects:    None.
  800. */
  801. /*-----------------------------------------------------------------------*/
  802. OSErr            ASoundSetSoundCallBack    (SoundInfoPtr theSoundInfo,
  803.                                         void* newValue)
  804. /*-----------------------------------------------------------------------*/
  805. {
  806.     OSErr        theErr        = noErr;
  807.  
  808.     if (IsValid (theSoundInfo)) {
  809.         if (theSoundInfo->theSoundCallBackUPP != nil) {
  810.             DisposeRoutineDescriptor (theSoundInfo->theSoundCallBackUPP);
  811.         }
  812.         if (newValue != nil) {
  813.             theSoundInfo->theSoundCallBackUPP = NewSndCallBackProc(newValue);
  814.         }
  815.         else {
  816.             theSoundInfo->theSoundCallBackUPP = NewSndCallBackProc(ASoundDoneCallBack);
  817.             DebugPrint ("\pDid you really want the default sound callback?");
  818.         }
  819.     }
  820.     else {
  821.         theErr = kNilPtrErr;
  822.     }
  823.  
  824.     if (theErr != noErr) {
  825.         DebugPrint ("\pError in ASoundSetSoundCallBack");
  826.     }
  827.  
  828.     return theErr;
  829. }
  830.  
  831. /*
  832.     Purpose:        Says whether to play the currently playing sound backwards
  833.                     (it actually reverses the sound in the buffer).
  834.     Side Effects:    Takes effect when the next sound buffer gets filled.
  835. */
  836. /*-----------------------------------------------------------------------*/
  837. OSErr            ASoundPlayBackwards        (SoundInfoPtr theSoundInfo,
  838.                                         Boolean newValue)
  839. /*-----------------------------------------------------------------------*/
  840. {
  841.     OSErr        theErr        = noErr;
  842.  
  843.     if (StrictIsValid (theSoundInfo)) {
  844.         theSoundInfo->backwards = newValue;
  845.     }
  846.     else {
  847.         theErr = kNilPtrErr;
  848.     }
  849.  
  850.     if (theErr != noErr) {
  851.         DebugPrint ("\pError in ASoundPlayBackwards");
  852.     }
  853.  
  854.     return theErr;
  855. }
  856.  
  857. /*
  858.     Purpose:        Returns true if the currently playing sound's buffer
  859.                     is set to be reversed.
  860.     Side Effects:    None.
  861. */
  862. /*-----------------------------------------------------------------------*/
  863. Boolean            ASoundIsBackwards        (SoundInfoPtr theSoundInfo)
  864. /*-----------------------------------------------------------------------*/
  865. {
  866.     OSErr        theErr            = noErr;
  867.     Boolean        returnValue        = false;
  868.  
  869.     if (StrictIsValid (theSoundInfo)) {
  870.         returnValue = theSoundInfo->backwards;
  871.     }
  872.     else {
  873.         theErr = kNilPtrErr;
  874.     }
  875.  
  876.     if (theErr != noErr) {
  877.         DebugPrint ("\pError in ASoundIsBackwards");
  878.     }
  879.  
  880.     return returnValue;
  881. }
  882.  
  883. /*
  884.     Purpose:        Returns true if the sound has finished playing.
  885.     Side Effects:    None.
  886. */
  887. /*-----------------------------------------------------------------------*/
  888. Boolean            ASoundIsDone            (SoundInfoPtr theSoundInfo)
  889. /*-----------------------------------------------------------------------*/
  890. {
  891.     OSErr        theErr            = noErr;
  892.     Boolean        returnValue        = false;
  893.  
  894.     if (StrictIsValid (theSoundInfo)) {
  895.         returnValue = theSoundInfo->soundDone;
  896.     }
  897.     else {
  898.         theErr = kNilPtrErr;
  899.     }
  900.  
  901.     if (theErr != noErr) {
  902.         DebugPrint ("\pError in ASoundIsDone");
  903.     }
  904.  
  905.     return returnValue;
  906. }
  907.  
  908. /*
  909.     Purpose:        Changes the volume of the currently playing sound.
  910.                     The values you pass in are added to the current values.
  911.                     Negitive values will decrease the volume, positive values
  912.                     will increase the volume.
  913.     Side Effects:    None.
  914. */
  915. /*-----------------------------------------------------------------------*/
  916. OSErr            ASoundChangeVolume        (SoundInfoPtr theSoundInfo,
  917.                                         unsigned short leftVol,
  918.                                         unsigned short rightVol)
  919. /*-----------------------------------------------------------------------*/
  920. {
  921.     SndCommand        theCmd        = {volumeCmd, kInit, kInit};
  922.     OSErr            theErr        = noErr;
  923.     unsigned short    tempLeft    = kInit,
  924.                     tempRight    = kInit;
  925.  
  926.     if (StrictIsValid (theSoundInfo)) {
  927.         theErr = ASoundGetVolume (theSoundInfo, &tempLeft, &tempRight);
  928.         if (theErr == noErr) {
  929.             if ((tempLeft + leftVol) > kMaxVolume) leftVol = kMaxVolume - tempLeft;
  930.             if ((tempRight + rightVol) > kMaxVolume) rightVol = kMaxVolume - tempRight;
  931.             if ((tempLeft + leftVol) < kMinVolume) leftVol = -tempLeft;
  932.             if ((tempRight + rightVol) < kMinVolume) rightVol = -tempRight;
  933.             theErr = ASoundSetVolume (theSoundInfo, tempLeft+leftVol, tempRight+rightVol);
  934.         }
  935.     }
  936.     else {
  937.         theErr = kNilPtrErr;
  938.     }
  939.  
  940.     if (theErr != noErr) {
  941.         DebugPrint ("\pError in ASoundChangeVolume");
  942.     }
  943.  
  944.     return theErr;
  945. }
  946.  
  947. /*
  948.     Purpose:        Gets the volume of the currently playing sound.
  949.     Side Effects:    None.
  950. */
  951. /*-----------------------------------------------------------------------*/
  952. OSErr            ASoundGetVolume            (SoundInfoPtr theSoundInfo,
  953.                                         unsigned short *leftVol,
  954.                                         unsigned short *rightVol)
  955. /*-----------------------------------------------------------------------*/
  956. {
  957.     SndCommand        theCmd        = {getVolumeCmd, kInit, kInit};
  958.     unsigned long    theVol        = kInit;
  959.     OSErr            theErr        = noErr;
  960.  
  961.     if (StrictIsValid (theSoundInfo)) {
  962.         theCmd.param2 = (long)&theVol;
  963.         theErr = SndDoImmediate(theSoundInfo->chan, &theCmd);
  964.  
  965.         if (theErr == noErr) {
  966.             *leftVol = theVol & kLeftMask;
  967.             *rightVol = theVol >> kSixteen;
  968.         }
  969.     }
  970.     else {
  971.         theErr = kNilPtrErr;
  972.     }
  973.  
  974.     if (theErr != noErr) {
  975.         DebugPrint ("\pError in ASoundGetVolume");
  976.     }
  977.  
  978.     return theErr;
  979. }
  980.  
  981. /*
  982.     Purpose:        Sets the volume of the currently playing sound.
  983.     Side Effects:    None.
  984. */
  985. /*-----------------------------------------------------------------------*/
  986. OSErr            ASoundSetVolume            (SoundInfoPtr theSoundInfo,
  987.                                         unsigned short leftVol,
  988.                                         unsigned short rightVol)
  989. /*-----------------------------------------------------------------------*/
  990. {
  991.     SndCommand        theCmd        = {volumeCmd, kInit, kInit};
  992.     OSErr            theErr        = noErr;
  993.  
  994.     if (StrictIsValid (theSoundInfo)) {
  995.         theCmd.param2 = (rightVol << kSixteen) | leftVol;
  996.         theErr = SndDoImmediate(theSoundInfo->chan, &theCmd);
  997.     }
  998.     else {
  999.         theErr = kNilPtrErr;
  1000.     }
  1001.  
  1002.     if (theErr != noErr) {
  1003.         DebugPrint ("\pError in ASoundSetVolume");
  1004.     }
  1005.  
  1006.     return theErr;
  1007. }
  1008.  
  1009. /*
  1010.     Purpose:        Gets the rate multiplier of the currently playing sound.
  1011.     Side Effects:    None.
  1012. */
  1013. /*-----------------------------------------------------------------------*/
  1014. OSErr            ASoundGetRateMul        (SoundInfoPtr theSoundInfo,
  1015.                                         UnsignedFixed *theRateMul)
  1016. /*-----------------------------------------------------------------------*/
  1017. {
  1018.     SndCommand        theCmd        = {getRateMultiplierCmd, kInit, kInit};
  1019.     OSErr            theErr        = noErr;
  1020.  
  1021.     if (StrictIsValid (theSoundInfo)) {
  1022.         theCmd.param2 = (long)theRateMul;
  1023.         theErr = SndDoImmediate(theSoundInfo->chan, &theCmd);
  1024.     }
  1025.     else {
  1026.         theErr = kNilPtrErr;
  1027.     }
  1028.  
  1029.     if (theErr != noErr) {
  1030.         DebugPrint ("\pError in ASoundGetRateMul");
  1031.     }
  1032.  
  1033.     return theErr;
  1034. }
  1035.  
  1036. /*
  1037.     Purpose:        Gets the rate multiplier of the currently playing sound.
  1038.     Side Effects:    None.
  1039. */
  1040. /*-----------------------------------------------------------------------*/
  1041. OSErr            ASoundSetRateMul        (SoundInfoPtr theSoundInfo,
  1042.                                         UnsignedFixed theRateMul)
  1043. /*-----------------------------------------------------------------------*/
  1044. {
  1045.     SndCommand        theCmd        = {rateMultiplierCmd, kInit, kInit};
  1046.     OSErr            theErr        = noErr;
  1047.  
  1048.     if (StrictIsValid (theSoundInfo)) {
  1049.         theCmd.param2 = (long)theRateMul;
  1050.         theErr = SndDoImmediate(theSoundInfo->chan, &theCmd);
  1051.     }
  1052.     else {
  1053.         theErr = kNilPtrErr;
  1054.     }
  1055.  
  1056.     if (theErr != noErr) {
  1057.         DebugPrint ("\pError in ASoundSetRateMul");
  1058.     }
  1059.  
  1060.     return theErr;
  1061. }
  1062.